package com.hjj.homieMatching.service.impl;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hjj.homieMatching.common.ErrorCode;
import com.hjj.homieMatching.exception.BusinessException;
import com.hjj.homieMatching.mapper.ChatMapper;
import com.hjj.homieMatching.model.domain.Chat;
import com.hjj.homieMatching.model.domain.Friend;
import com.hjj.homieMatching.model.domain.Team;
import com.hjj.homieMatching.model.domain.User;
import com.hjj.homieMatching.model.request.ChatRequest;
import com.hjj.homieMatching.model.request.MessageRequest;
import com.hjj.homieMatching.model.vo.ChatMessageVO;
import com.hjj.homieMatching.model.vo.PrivateMessageVO;
import com.hjj.homieMatching.model.vo.WebSocketVO;
import com.hjj.homieMatching.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.hjj.homieMatching.constant.ChatConstant.*;
import static com.hjj.homieMatching.constant.RedisConstant.*;
import static com.hjj.homieMatching.constant.UserConstant.ADMIN_ROLE;


@Service
public class ChatServiceImpl extends ServiceImpl<ChatMapper, Chat>
        implements ChatService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private UserService userService;

    @Resource
    private TeamService teamService;

    @Resource
    private FriendService friendService;

    @Resource
    private UserTeamService userTeamService;

    /**
     * 获取私人聊天
     *
     * @param chatRequest 聊天请求
     * @param chatType    聊天类型
     * @param loginUser   登录用户
     * @return {@link List}<{@link ChatMessageVO}>
     */
    @Override
    public List<ChatMessageVO> getPrivateChat(ChatRequest chatRequest, int chatType, User loginUser) {
        Long toId = chatRequest.getToId();
        if (toId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        // 创建缓存key，确保相同的两个用户有相同的key
        String cacheKey = Math.min(loginUser.getId(), toId) + String.valueOf(Math.max(loginUser.getId(), toId));
        List<ChatMessageVO> chatRecords = getCache(CACHE_CHAT_PRIVATE, cacheKey);

        // 如果缓存存在，验证聊天记录中的发送者和接收者信息是否正确
        if (chatRecords != null) {
            // 确保每条消息的发送者和接收者信息设置正确
            for (ChatMessageVO message : chatRecords) {
                // 重新设置是否为自己发送的标志
                boolean isMy = message.getFromUser().getId() == loginUser.getId();
                message.setIsMy(isMy);
            }
            return chatRecords;
        }

        // 从数据库获取聊天记录
        LambdaQueryWrapper<Chat> chatLambdaQueryWrapper = new LambdaQueryWrapper<>();
        chatLambdaQueryWrapper.
                and(privateChat -> privateChat.eq(Chat::getFromId, loginUser.getId()).eq(Chat::getToId, toId)
                        .or().
                        eq(Chat::getToId, loginUser.getId()).eq(Chat::getFromId, toId)
                ).eq(Chat::getChatType, chatType);

        // 获取聊天记录
        List<Chat> list = this.list(chatLambdaQueryWrapper);
        List<ChatMessageVO> chatMessageVOList = new ArrayList<>();

        // 获取对方的用户信息
        User otherUser = userService.getById(toId);
        if (otherUser == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "接收用户不存在");
        }

        // 构建聊天消息VO对象
        for (Chat chat : list) {
            ChatMessageVO chatMessageVO = new ChatMessageVO();
            
            // 设置发送者信息
            User fromUser = chat.getFromId() == loginUser.getId() ? loginUser : otherUser;
            WebSocketVO fromWebSocketVO = new WebSocketVO();
            BeanUtils.copyProperties(fromUser, fromWebSocketVO);
            chatMessageVO.setFromUser(fromWebSocketVO);
            
            // 设置接收者信息
            User toUser = chat.getToId() == loginUser.getId() ? loginUser : otherUser;
            WebSocketVO toWebSocketVO = new WebSocketVO();
            BeanUtils.copyProperties(toUser, toWebSocketVO);
            chatMessageVO.setToUser(toWebSocketVO);
            
            chatMessageVO.setText(chat.getText());
            chatMessageVO.setChatType(chatType);
            chatMessageVO.setCreateTime(DateUtil.format(chat.getCreateTime(), "yyyy年MM月dd日 HH:mm"));

            // 设置是否为自己发送的消息
            chatMessageVO.setIsMy(chat.getFromId() == loginUser.getId());

            chatMessageVOList.add(chatMessageVO);
        }

        // 保存缓存并返回结果
        saveCache(CACHE_CHAT_PRIVATE, cacheKey, chatMessageVOList);
        return chatMessageVOList;
    }

    /**
     * 获取缓存
     *
     * @param redisKey redis键
     * @param id       id
     * @return {@link List}<{@link ChatMessageVO}>
     */
    @Override
    @SuppressWarnings("unchecked")
    public List<ChatMessageVO> getCache(String redisKey, String id) {
        ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
        List<ChatMessageVO> chatRecords;
        if (redisKey.equals(CACHE_CHAT_HALL)) {
            chatRecords = (List<ChatMessageVO>) valueOperations.get(redisKey);
        } else {
            chatRecords = (List<ChatMessageVO>) valueOperations.get(redisKey + id);
        }
        return chatRecords;
    }

    /**
     * 保存缓存
     *
     * @param redisKey       redis键
     * @param id             id
     * @param chatMessageVOS 聊天消息vos
     */
    @Override
    public void saveCache(String redisKey, String id, List<ChatMessageVO> chatMessageVOS) {
        try {
            ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
            // 解决缓存雪崩
            int i = RandomUtil.randomInt(MINIMUM_CACHE_RANDOM_TIME, MAXIMUM_CACHE_RANDOM_TIME);
            if (redisKey.equals(CACHE_CHAT_HALL)) {
                valueOperations.set(
                        redisKey,
                        chatMessageVOS,
                        MINIMUM_CACHE_RANDOM_TIME + i / CACHE_TIME_OFFSET,
                        TimeUnit.MINUTES);
            } else {
                valueOperations.set(
                        redisKey + id,
                        chatMessageVOS,
                        MINIMUM_CACHE_RANDOM_TIME + i / CACHE_TIME_OFFSET,
                        TimeUnit.MINUTES);
            }
        } catch (Exception e) {
            log.error("redis set key error");
        }
    }

    /**
     * 聊天结果
     *
     * @param userId 用户id
     * @param text   文本
     * @return {@link ChatMessageVO}
     */
    private ChatMessageVO chatResult(Long userId, String text) {
        ChatMessageVO chatMessageVo = new ChatMessageVO();
        User fromUser = userService.getById(userId);
        WebSocketVO fromWebSocketVo = new WebSocketVO();
        BeanUtils.copyProperties(fromUser, fromWebSocketVo);
        chatMessageVo.setFromUser(fromWebSocketVo);
        chatMessageVo.setText(text);
        return chatMessageVo;
    }

    /**
     * 聊天结果
     *
     * @param userId     用户id
     * @param toId       到id
     * @param text       文本
     * @param chatType   聊天类型
     * @param createTime 创建时间
     * @return {@link ChatMessageVO}
     */
    @Override
    public ChatMessageVO chatResult(Long userId, Long toId, String text, Integer chatType, Date createTime) {
        ChatMessageVO chatMessageVo = new ChatMessageVO();
        User fromUser = userService.getById(userId);
        WebSocketVO fromWebSocketVo = new WebSocketVO();
        BeanUtils.copyProperties(fromUser, fromWebSocketVo);
        chatMessageVo.setFromUser(fromWebSocketVo);
        
        // 添加空值检查，如果toId不为null才尝试获取接收用户信息
        if (toId != null) {
            User toUser = userService.getById(toId);
            if (toUser != null) {
                WebSocketVO toWebSocketVo = new WebSocketVO();
                BeanUtils.copyProperties(toUser, toWebSocketVo);
                chatMessageVo.setToUser(toWebSocketVo);
            }
        }
        
        chatMessageVo.setChatType(chatType);
        chatMessageVo.setText(text);
        chatMessageVo.setCreateTime(DateUtil.format(createTime, "yyyy-MM-dd HH:mm:ss"));
        return chatMessageVo;
    }

    /**
     * 删除密钥
     *
     * @param key 钥匙
     * @param id  id
     */
    @Override
    public void deleteKey(String key, String id) {
        if (key.equals(CACHE_CHAT_HALL)) {
            redisTemplate.delete(key);
        } else {
            redisTemplate.delete(key + id);
        }
    }

    /**
     * 获取团队聊天
     *
     * @param chatRequest 聊天请求
     * @param chatType    聊天类型
     * @param loginUser   登录用户
     * @return {@link List}<{@link ChatMessageVO}>
     */
    @Override
    public List<ChatMessageVO> getTeamChat(ChatRequest chatRequest, int chatType, User loginUser) {
        Long teamId = chatRequest.getTeamId();
        if (teamId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求有误");
        }
        List<ChatMessageVO> chatRecords = getCache(CACHE_CHAT_TEAM, String.valueOf(teamId));
        if (chatRecords != null) {
            List<ChatMessageVO> chatMessageVOS = checkIsMyMessage(loginUser, chatRecords);
            saveCache(CACHE_CHAT_TEAM, String.valueOf(teamId), chatMessageVOS);
            return chatMessageVOS;
        }
        // 判断用户是否在队伍中
        if (!userTeamService.teamHasUser(teamId, loginUser.getId())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "您还未加入此队伍");
        }
        Team team = teamService.getById(teamId);
        LambdaQueryWrapper<Chat> chatLambdaQueryWrapper = new LambdaQueryWrapper<>();
        chatLambdaQueryWrapper.eq(Chat::getChatType, chatType).eq(Chat::getTeamId, teamId);
        List<ChatMessageVO> chatMessageVOS = returnMessage(loginUser, team.getUserId(), chatLambdaQueryWrapper);
        saveCache(CACHE_CHAT_TEAM, String.valueOf(teamId), chatMessageVOS);
        return chatMessageVOS;
    }

    /**
     * 获得大厅聊天
     *
     * @param chatType  聊天类型
     * @param loginUser 登录用户
     * @return {@link List}<{@link ChatMessageVO}>
     */
    @Override
    public List<ChatMessageVO> getHallChat(int chatType, User loginUser) {
        List<ChatMessageVO> chatRecords = getCache(CACHE_CHAT_HALL, String.valueOf(loginUser.getId()));
        if (chatRecords != null) {
            List<ChatMessageVO> chatMessageVOS = checkIsMyMessage(loginUser, chatRecords);
            saveCache(CACHE_CHAT_HALL, String.valueOf(loginUser.getId()), chatMessageVOS);
            return chatMessageVOS;
        }
        LambdaQueryWrapper<Chat> chatLambdaQueryWrapper = new LambdaQueryWrapper<>();
        chatLambdaQueryWrapper.eq(Chat::getChatType, chatType);
        List<ChatMessageVO> chatMessageVOS = returnMessage(loginUser, null, chatLambdaQueryWrapper);
        saveCache(CACHE_CHAT_HALL, String.valueOf(loginUser.getId()), chatMessageVOS);
        return chatMessageVOS;
    }

    @Override
    public List<PrivateMessageVO> listPrivateChat(HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        long userId = loginUser.getId();
        List<Long> frinedIdList = friendService.list(new QueryWrapper<Friend>().eq("userId", userId))
                .stream().map(Friend::getFriendId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(frinedIdList)) {
            return new ArrayList<>();
        }
        List<Chat> privateMessageVOList = this.baseMapper.getLastPrivateChatMessages(userId, frinedIdList);
        return privateMessageVOList.stream().map(chat -> {
            PrivateMessageVO privateMessageVO = new PrivateMessageVO();
            privateMessageVO.setId(chat.getId());
            privateMessageVO.setText(chat.getText());
            privateMessageVO.setCreateTime(DateUtil.format(chat.getCreateTime(), "yyyy年MM月dd日 HH:mm:ss"));
            Long fromId = chat.getFromId();
            Long toId = chat.getToId();
            long friendId = 0L;
            if (fromId != userId) {
                friendId = fromId;
            }
            if (toId != userId) {
                friendId = toId;
            }
            privateMessageVO.setFriendId(friendId);
            User friend = userService.getById(friendId);
            privateMessageVO.setAvatarUrl(friend.getAvatarUrl());
            privateMessageVO.setUsername(friend.getUsername());
            return privateMessageVO;
        }).collect(Collectors.toList());
    }

    /**
     * 检查是我的信息
     *
     * @param loginUser   登录用户
     * @param chatRecords 聊天记录
     * @return {@link List}<{@link ChatMessageVO}>
     */
    private List<ChatMessageVO> checkIsMyMessage(User loginUser, List<ChatMessageVO> chatRecords) {
        return chatRecords.stream().peek(chat -> {
            if (chat.getFromUser().getId() != loginUser.getId() && chat.getIsMy()) {
                chat.setIsMy(false);
            }
            if (chat.getFromUser().getId() == loginUser.getId() && !chat.getIsMy()) {
                chat.setIsMy(true);
            }
        }).collect(Collectors.toList());
    }

    /**
     * 返回消息
     *
     * @param loginUser              登录用户
     * @param userId                 用户id
     * @param chatLambdaQueryWrapper 聊天lambda查询包装器
     * @return {@link List}<{@link ChatMessageVO}>
     */
    private List<ChatMessageVO> returnMessage(User loginUser,
                                              Long userId,
                                              LambdaQueryWrapper<Chat> chatLambdaQueryWrapper) {
        List<Chat> chatList = this.list(chatLambdaQueryWrapper);
        return chatList.stream().map(chat -> {
            ChatMessageVO chatMessageVo = chatResult(chat.getFromId(), chat.getText());
            boolean isCaptain = userId != null && userId.equals(chat.getFromId());
            if (userService.getById(chat.getFromId()).getUserRole() == ADMIN_ROLE || isCaptain) {
                chatMessageVo.setIsAdmin(true);
            }
            if (chat.getFromId().equals(loginUser.getId())) {
                chatMessageVo.setIsMy(true);
            }
            chatMessageVo.setCreateTime(DateUtil.format(chat.getCreateTime(), "yyyy年MM月dd日 HH:mm:ss"));
            return chatMessageVo;
        }).collect(Collectors.toList());
    }

    /**
     * 处理聊天消息
     *
     * @param loginUser      登录用户
     * @param messageRequest 消息请求
     * @return {@link ChatMessageVO} 处理后的消息
     */
    @Override
    public ChatMessageVO processMessage(User loginUser, MessageRequest messageRequest) {
        Long userId = loginUser.getId();
        Long toId = messageRequest.getToId();
        Long teamId = messageRequest.getTeamId();
        String text = messageRequest.getText();
        Integer chatType = messageRequest.getChatType();
        Date createTime = new Date();
        
        // 保存聊天记录到数据库
        Chat chat = new Chat();
        chat.setFromId(userId);
        chat.setText(text);
        chat.setChatType(chatType);
        chat.setCreateTime(createTime);
        
        if (toId != null && toId > 0) {
            chat.setToId(toId);
        }
        
        if (teamId != null && teamId > 0) {
            chat.setTeamId(teamId);
        }
        
        boolean saved = this.save(chat);
        if (!saved) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "消息保存失败");
        }
        
        // 构建返回的消息对象
        ChatMessageVO result = new ChatMessageVO();
        
        // 根据聊天类型处理不同的聊天情况
        if (chatType == PRIVATE_CHAT) {
            // 私聊
            User toUser = userService.getById(toId);
            if (toUser == null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "接收用户不存在");
            }
            
            // 构建私聊消息并更新缓存
            result = processPrivateChat(userId, toId, text, chatType, createTime, loginUser, toUser);
            
        } else if (chatType == TEAM_CHAT) {
            // 团队聊天
            if (teamId == null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "团队ID不能为空");
            }
            
            Team team = teamService.getById(teamId);
            if (team == null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍不存在");
            }
            
            // 检查用户是否在团队中
            boolean isUserInTeam = userTeamService.teamHasUser(teamId, userId);
            if (!isUserInTeam) {
                throw new BusinessException(ErrorCode.FORBIDDEN, "您不在该队伍中，无法发送消息");
            }
            
            // 构建团队聊天消息并更新缓存
            result = processTeamChat(userId, teamId, text, chatType, createTime, loginUser);
            
        } else if (chatType == HALL_CHAT) {
            // 大厅聊天
            result = processHallChat(userId, text, chatType, createTime, loginUser);
        } else {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "不支持的聊天类型");
        }
        
        return result;
    }
    
    /**
     * 处理私聊消息
     */
    private ChatMessageVO processPrivateChat(Long userId, Long toId, String text, Integer chatType, Date createTime, 
                                            User fromUser, User toUser) {
        // 构建消息对象
        ChatMessageVO chatMessageVO = chatResult(userId, toId, text, chatType, createTime);
        WebSocketVO fromWebSocketVO = new WebSocketVO();
        BeanUtils.copyProperties(fromUser, fromWebSocketVO);
        chatMessageVO.setFromUser(fromWebSocketVO);
        WebSocketVO toWebSocketVO = new WebSocketVO();
        BeanUtils.copyProperties(toUser, toWebSocketVO);
        chatMessageVO.setToUser(toWebSocketVO);
        chatMessageVO.setText(text);
        chatMessageVO.setIsMy(true);
        chatMessageVO.setChatType(chatType);
        chatMessageVO.setCreateTime(DateUtil.format(createTime, "yyyy年MM月dd日 HH:mm"));
        
        // 获取私聊缓存
        String redisKey = CACHE_CHAT_PRIVATE;
        String key = Math.min(userId, toId) + String.valueOf(Math.max(userId, toId));
        List<ChatMessageVO> chatMessageVOList = getCache(redisKey, key);
        if (chatMessageVOList == null) {
            chatMessageVOList = new ArrayList<>();
        }
        
        // 添加消息到缓存列表
        chatMessageVOList.add(chatMessageVO);
        saveCache(redisKey, key, chatMessageVOList);
        
        return chatMessageVO;
    }
    
    /**
     * 处理团队聊天消息
     */
    private ChatMessageVO processTeamChat(Long userId, Long teamId, String text, Integer chatType, Date createTime, User fromUser) {
        // 构建消息对象
        ChatMessageVO chatMessageVO = chatResult(userId, null, text, chatType, createTime);
        WebSocketVO fromWebSocketVO = new WebSocketVO();
        BeanUtils.copyProperties(fromUser, fromWebSocketVO);
        chatMessageVO.setFromUser(fromWebSocketVO);
        chatMessageVO.setText(text);
        chatMessageVO.setTeamId(teamId);
        chatMessageVO.setChatType(chatType);
        chatMessageVO.setCreateTime(DateUtil.format(createTime, "yyyy年MM月dd日 HH:mm"));
        
        // 获取团队聊天缓存
        String redisKey = CACHE_CHAT_TEAM;
        String key = String.valueOf(teamId);
        List<ChatMessageVO> chatMessageVOList = getCache(redisKey, key);
        if (chatMessageVOList == null) {
            chatMessageVOList = new ArrayList<>();
        }
        
        // 添加消息到缓存列表
        chatMessageVOList.add(chatMessageVO);
        saveCache(redisKey, key, chatMessageVOList);
        
        return chatMessageVO;
    }
    
    /**
     * 处理大厅聊天消息
     */
    private ChatMessageVO processHallChat(Long userId, String text, Integer chatType, Date createTime, User fromUser) {
        // 构建消息对象
        ChatMessageVO chatMessageVO = chatResult(userId, null, text, chatType, createTime);
        WebSocketVO fromWebSocketVO = new WebSocketVO();
        BeanUtils.copyProperties(fromUser, fromWebSocketVO);
        chatMessageVO.setFromUser(fromWebSocketVO);
        chatMessageVO.setText(text);
        chatMessageVO.setChatType(chatType);
        chatMessageVO.setCreateTime(DateUtil.format(createTime, "yyyy年MM月dd日 HH:mm"));
        
        if (fromUser.getUserRole() == ADMIN_ROLE) {
            chatMessageVO.setIsAdmin(true);
        }
        
        // 获取大厅聊天缓存
        List<ChatMessageVO> chatMessageVOList = getCache(CACHE_CHAT_HALL, null);
        if (chatMessageVOList == null) {
            chatMessageVOList = new ArrayList<>();
        }
        
        // 添加消息到缓存列表
        chatMessageVOList.add(chatMessageVO);
        saveCache(CACHE_CHAT_HALL, null, chatMessageVOList);
        
        return chatMessageVO;
    }
}
